/*sched_tester.c: Test program.  Invokes tasks. The policy of all the 
tasks created by the program is SCHED_BRR.   
Tasks perform a recursive calculation of the Fibonacci number*/

#include <asm/errno.h>
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "hw2_syscalls.h"

typedef struct {
	int number_of_trials;
	int fib_num;
}argument;

#define SWITCH_INFO_LIST_LENGTH		150
#define SWITCH_INFO_LIST_SIZE		sizeof(struct switch_info) * SWITCH_INFO_LIST_LENGTH

typedef struct switch_info switch_info_list[SWITCH_INFO_LIST_LENGTH];

int fibonacci(int n);

int main(int argc, char *argv[]) {
	if (argc < 3 || argc%2 != 1) {
		printf("Invalid arguments. Argument syntax should be:\nsched_tester \
			   sched_tester <number_of_trials1> <n1> <number_of_trials2> <n2>...\n\
			   (Minimum of 1 pair of arguments)\n");
		return -EINVAL;
	}

	int argListSize = argc / 2;
	argument* argList = (argument*) malloc(sizeof(argument) * argListSize);
	if(!argList) {
		printf("Could not allocate memory.\n");
		return -ENOMEM;
	}

	int i_argv,i_argList;
	for (i_argv = 1, i_argList = 0; i_argList < argListSize; i_argList++) {
		argList[i_argList].number_of_trials = atoi(argv[i_argv++]);
		argList[i_argList].fib_num = atoi(argv[i_argv++]);
	}
	pid_t pid;
	int i;
	printf("Father: pid: %d\n", getpid());
	for (i = 0; i < argListSize; i++) {
		if(!(pid = fork())) { //child process
			struct sched_param params;
			params.sched_priority = 0;
			params.trial_num = argList[i].number_of_trials;
			int setschedres = sched_setscheduler(getpid(), SCHED_BRR, &params);
			if(setschedres < 0) {
				printf("sched_setscheduler failed with retval %d\n",errno);
			}
			printf("Child #%d, pid: %d, Is Brr: %d\n", i, getpid(), is_brr(getpid()));
			return fibonacci(argList[i].fib_num);
			
		} else { //father process or error
			if (pid < 0){ //error
				printf("Failed to create #%d child process\n", i);
				return pid;
			}
		}
	}

	int status;
	// wait for all children to finish
	while (wait(&status) > 0) {
	}

	struct switch_info* sil = (struct switch_info*) malloc (SWITCH_INFO_LIST_SIZE);
	if (!sil) {
		printf ("Couldn't allocate memory\n");
		free(argList);
		return -1;
	}
	int silSize;
	if ((silSize = get_scheduling_statistic(sil)) < 0) {
		printf("get_scheduling_statistic: Failed\n");
		return -1;
	}

	for (i = 0; i < silSize; i++) {
		printf("previous pid: %d\tnext pid: %d\tprevious policy: %d\tnext policy: %d\ttime: %d\treason: %d\n", 
			sil[i].previous_pid, 
			sil[i].next_pid, 
			sil[i].previous_policy, 
			sil[i].next_policy,
			sil[i].time,
			sil[i].reason);
	}


	//free allocations
	free(argList);
	free(sil);
}

int fibonacci(int n) {
	if (n < 2) {
		return n;
	}
	return fibonacci(n - 1) + fibonacci(n - 2);
}
